package fr.emse.tatiana.replayable.analysis;

import java.util.List;
import java.util.Vector;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.Graphics;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.editparts.ScalableRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.palette.ConnectionCreationToolEntry;
import org.eclipse.gef.palette.MarqueeToolEntry;
import org.eclipse.gef.palette.PaletteGroup;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.palette.PaletteSeparator;
import org.eclipse.gef.palette.PanningSelectionToolEntry;
import org.eclipse.gef.palette.ToolEntry;
import org.eclipse.gef.requests.CreationFactory;
import org.eclipse.gef.tools.AbstractTool;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.ZoomInAction;
import org.eclipse.gef.ui.actions.ZoomOutAction;
import org.eclipse.gef.ui.parts.GraphicalEditorWithPalette;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import fr.emse.tatiana.replayable.analysis.graph.DeleteAction;
import fr.emse.tatiana.replayable.analysis.graph.GraphAnalysisPartFactory;
import fr.emse.tatiana.replayable.analysis.graph.GraphContextMenuProvider;
import fr.emse.tatiana.replayable.analysis.graph.RenameAction;
import fr.emse.tatiana.graphical.DisplayRule;

public class GraphEditor extends GraphicalEditorWithPalette {

	public GraphAnalysis model;
	List<DisplayRule> rules;

	public GraphEditor(GraphAnalysis model, List<DisplayRule> rules) {
		setEditDomain(new DefaultEditDomain(this));
		this.model = model;
		this.rules = rules;
	}

	@Override
	protected void configureGraphicalViewer() {
		super.configureGraphicalViewer();   
		GraphicalViewer viewer = getGraphicalViewer();
		viewer.setEditPartFactory(new GraphAnalysisPartFactory());
		ScalableRootEditPart root = new ScalableRootEditPart();
		viewer.setRootEditPart(root);

		ZoomManager zmanager = root.getZoomManager();
		getActionRegistry().registerAction(new ZoomInAction(zmanager));
		getActionRegistry().registerAction(new ZoomOutAction(zmanager));
		double[] zoomlevels = new double[]{0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 2.5, 3.0};
		zmanager.setZoomLevels(zoomlevels);
		//zmanager.setZoom(2.0);
//		KeyHandler kh = new KeyHandler();

//		kh.put(KeyStroke.getPressed('i',0),
//		getActionRegistry().getAction(GEFActionConstants.ZOOM_IN));
//		kh.put(KeyStroke.getPressed('o',0),
//		getActionRegistry().getAction(GEFActionConstants.ZOOM_OUT));
//		viewer.setKeyHandler(kh);
		ContextMenuProvider provider = new GraphContextMenuProvider(viewer,getActionRegistry());
		viewer.setContextMenu(provider);

	}



	@Override
	protected void initializeGraphicalViewer() {
		GraphicalViewer viewer = getGraphicalViewer();
		viewer.setContents(model);
		refresh();
	}

	public GraphicalViewer getViewer() {
		return getGraphicalViewer();
	}


	public void refresh() {
		EditPart part = ((GraphAnalysisPartFactory)getGraphicalViewer().getEditPartFactory()).getEditPart(model);
		part.refresh();
		List<Link> links = model.getLinks(); 
		for (int i=0; i<links.size(); i++) {
			Link lk = links.get(i);
			((GraphAnalysisPartFactory)getGraphicalViewer().getEditPartFactory()).getEditPart(lk).refresh();
		}
	}

	@Override
	protected PaletteRoot getPaletteRoot() {
		PaletteRoot root = new PaletteRoot();
		PaletteGroup toolGroup = new PaletteGroup("Tools");

		// Add a selection tool to the group
		ToolEntry tool = new PanningSelectionToolEntry();
		toolGroup.add(tool);
		root.setDefaultEntry(tool);
		// Add a marquee tool to the group
		toolGroup.add(new MarqueeToolEntry());

		// Add a (unnamed) separator to the group
		toolGroup.add(new PaletteSeparator());

		// Add (solid-line) connection tool 
		tool = new ConnectionCreationToolEntry(
				"Link",
				"Create a solid-line link",
				new CreationFactory() {
					public Object getNewObject() { return null; }
					// see ShapeEditPart#createEditPolicies() 
					// this is abused to transmit the desired line style 
					public Object getObjectType() { return Graphics.LINE_SOLID; }
				},
				null,
				null);
		tool.setToolProperty(AbstractTool.PROPERTY_UNLOAD_WHEN_FINISHED,
				Boolean.TRUE);

		toolGroup.add(tool);
		
		tool = new ConnectionCreationToolEntry(
				"Dashed Link",
				"Create a dashed-line link",
				new CreationFactory() {
					public Object getNewObject() { return null; }
					// see ShapeEditPart#createEditPolicies() 
					// this is abused to transmit the desired line style 
					public Object getObjectType() { return Graphics.LINE_DASH; }
				},
				null,
				null);
		tool.setToolProperty(AbstractTool.PROPERTY_UNLOAD_WHEN_FINISHED,
				Boolean.TRUE);

		toolGroup.add(tool);
		
		tool = new ConnectionCreationToolEntry(
				"Dotted Link",
				"Create a dotted-line link",
				new CreationFactory() {
					public Object getNewObject() { return null; }
					// see ShapeEditPart#createEditPolicies() 
					// this is abused to transmit the desired line style 
					public Object getObjectType() { return Graphics.LINE_DOT; }
				},
				null,
				null);
		tool.setToolProperty(AbstractTool.PROPERTY_UNLOAD_WHEN_FINISHED,
				Boolean.TRUE);

		toolGroup.add(tool);

		// Add (dashed-line) connection tool
//		tool = new ConnectionCreationToolEntry(
//		"Dashed connection",
//		"Create a dashed-line connection",
//		new CreationFactory() {
//		public Object getNewObject() { return null; }
//		// see ShapeEditPart#createEditPolicies()
//		// this is abused to transmit the desired line style 
//		public Object getObjectType() { return Connection.DASHED_CONNECTION; }
//		},
//		ImageDescriptor.createFromFile(ShapesPlugin.class, "icons/connection_d16.gif"),
//		ImageDescriptor.createFromFile(ShapesPlugin.class, "icons/connection_d24.gif"));
//		toolGroup.add(tool);

		root.add(toolGroup);
		return root;
	}

	public IAnalysis getAnalysis() {
		return model;
	}

	@Override
	public void doSave(IProgressMonitor monitor) {
		// do nothing
	}

	@Override
	public void createActions() {
		super.createActions();
		ActionRegistry r = getActionRegistry();
		IAction a = new RenameAction(this);
		r.registerAction(a);
		getSelectionActions().add(a.getId());
		a = new DeleteAction(this); //TODO look into using GEF default
		r.registerAction(a);
		getSelectionActions().add(a.getId());
	}


	public void setSelection(StructuredSelection selection) {
		List<EditPart> partlist = new Vector<EditPart>();
		List<Object> modelsellist = selection.toList();
		for (Object o: modelsellist) {
			EditPart part = ((GraphAnalysisPartFactory)getGraphicalViewer().getEditPartFactory()).getEditPart(o);
			if (part!=null) partlist.add(part);
		}
		IStructuredSelection partsel = StructuredSelection.EMPTY;
		if (partlist.size()>0) 
		{
			partsel = new StructuredSelection(partlist);
			getGraphicalViewer().reveal(partlist.get(0)); // maybe the order here is why events aren't revealed.
		}
		this.getViewer().setSelection(partsel);
	}

	@Override
	public Object getAdapter(Class type) {
		if (type==ZoomManager.class)
			return ((ScalableRootEditPart) getGraphicalViewer().getRootEditPart()).getZoomManager();
		return super.getAdapter(type);
	}


}
